package com.tomvian.screens 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Stage;
	import com.tomvian.screens.AbstractTransition;
	import org.osflash.signals.Signal;
	/**
	 * ScreenManager
	 * @author Thomas Vian
	 */
	public class ScreenManager
	{
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		
		public static const NONE:uint = 	0;
		public static const PUSH:uint = 	1;
		public static const POP:uint = 		2;
		public static const REPLACE:uint = 	3;
		
		public static var stage:Stage;
		
		public var onSwapStart:Signal = new Signal;
		public var onSwapFinish:Signal = new Signal;
		
		protected var _canvas:DisplayObjectContainer;
		
		public var _currentScreen:AbstractScreen;
		public var _previousScreen:AbstractScreen;
		
		protected var _screenStack:Array;
		protected var _stackLength:uint;
		
		protected var _currentTransition:AbstractTransition;
		
		protected var _background:DisplayObject;
		protected var _foreground:DisplayObject;
		
		protected var _currentOperation:uint;
		
		//--------------------------------------------------------------------------
		//
		//  Getters / Setters
		//
		//--------------------------------------------------------------------------
		
		public function get background():DisplayObject { return _background; }
		public function set background(value:DisplayObject):void
		{
			if (_background && _canvas.contains(_background)) _canvas.removeChild(_background);
			
			_background = value;
			
			if(_background) _canvas.addChildAt(_background, 0);
		}
		
		public function get foreground():DisplayObject { return _foreground; }
		public function set foreground(value:DisplayObject):void
		{
			if (_foreground && _canvas.contains(_foreground)) _canvas.removeChild(_foreground);
			
			_foreground = value;
			
			if (_foreground) _canvas.addChild(_foreground);
		}
		
		public function get currentOperation():uint { return _currentOperation; }
		
		public function get canvas():DisplayObjectContainer 
		{
			return _canvas;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		
		public function ScreenManager(canvas:DisplayObjectContainer) 
		{
			_canvas = canvas;
			stage = _canvas.stage;
			
			_screenStack = [];
			_stackLength = 0;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Public Methods
		//
		//--------------------------------------------------------------------------
		
		public function pushScreen(screen:AbstractScreen, transition:AbstractTransition = null, showScreen:Boolean = true):void
		{
			_screenStack.push(screen);
			_stackLength++;
			
			if (showScreen) 
			{
				_currentOperation = PUSH;
				transitionTo(screen, transition);
			}
		}
		
		public function replaceScreen(screen:AbstractScreen, transition:AbstractTransition = null, showScreen:Boolean = true):void
		{
			_screenStack[_stackLength] = screen;
			
			if (showScreen) 
			{
				_currentOperation = REPLACE;
				transitionTo(screen, transition);
			}
		}
		
		public function popScreen(transition:AbstractTransition = null, showScreen:Boolean = true):void
		{
			if (_stackLength > 0)
			{
				_screenStack.pop();
				_stackLength--;
				var screen:AbstractScreen = _screenStack[_stackLength];
				
				if (showScreen) 
				{
					_currentOperation = POP;
					transitionTo(screen, transition);
				}
			}
		}
		
		//--------------------------------------------------------------------------
		//
		//  Behind the screens Methods
		//
		//--------------------------------------------------------------------------
		
		protected function transitionTo(screen:AbstractScreen, transition:AbstractTransition):void
		{
			screen.screenManager = this;
			
			onSwapStart.dispatch();
			
			if(transition)
			{
				transition.screenManager = this;
				_currentTransition = transition;
				_currentTransition.play(_currentScreen, screen);
			}
			else
			{
				swapTo(screen);
				finishTransition();
			}
		}
		
		internal function swapTo(screen:AbstractScreen, inTransition:Boolean = false, overlap:Boolean = false, inFront:Boolean = true):void
		{
			_previousScreen = _currentScreen;
			_currentScreen = screen;
			
			if (_previousScreen)
			{
				if (!inTransition) _previousScreen.exitStart(_currentScreen);
				if (!overlap) _canvas.removeChild(_previousScreen.graphic);
			}
			
			if (inFront) 	_canvas.addChild(_currentScreen.graphic);
			else 			_canvas.addChildAt(_currentScreen.graphic, _canvas.getChildIndex(_previousScreen.graphic));
			
			if (_foreground) _canvas.addChild(_foreground);
			
			_currentScreen.enterStart(_previousScreen);
			
			if (_previousScreen && !overlap) 
			{
				_previousScreen.exitFinish(_currentScreen);
				_previousScreen.screenManager = null;
			}
			
			if (!inTransition) _currentScreen.enterFinish(_previousScreen);
		}
		
		internal function finishTransition():void
		{
			onSwapFinish.dispatch();
			
			_currentOperation = NONE;
		}
		
		public function clear():void
		{
			if (_currentScreen)
			{
				_currentScreen.exitStart(null);
				_currentScreen.exitFinish(null);
				_canvas.removeChild(_currentScreen.graphic);
				
				_currentScreen = null;
				_previousScreen = null;
			}
		}
	}
}